WICONF.initZTree = {
    nNodeH: 30,// 每个节点的高度，与 css 中 .ztree li>a 一致
    view: {
        fontCss: function(treeId, treeNode){
            // 根据 treeNode.__hlight 设置节点样式
            return !!treeNode.__hlight ?
            {color: '#A60000', fontWeight: 'bold'} :
            {color: '#333', fontWeight: 'normal'};
        },
        showLine: true,// 显示树线
        showIcon: true// 显示节点图标
    }
};
/**
 * @widoc $.fn.initZTree
 * @namespace comp
 * @des 初始化 tree。用于初始化的元素必须为 &lt;ul&gt;&lt;/ul&gt;，如果需要在过滤时将匹配节点滚动至可视区，需要令滚动条出现在初始化元素上（即：有一定高度，且 overflow-y:auto）。此组件在 zTree 基础上扩展，未做扩展的接口请查看：http://www.treejs.cn/v3/api.php
 * 组件配置，在使用组件前调用：
 <pre class="des-conf"> $.setWiConf('initZTree',{
    nNodeH:30,// 每个节点的高度，与 css 种 .ztree li>a 一致
    view:{
        fontCss: function(treeId, treeNode){
            // 根据 treeNode.__hlight 设置节点样式
            return !!treeNode.__hlight ?
            {color: '#A60000', fontWeight: 'bold'} :
            {color: '#333', fontWeight: 'normal'};
        },
        showLine:true,// 显示树线
        showIcon:true// 显示节点图标
    }
 });</pre>
 * @type function
 * @demo initZTree/demo0 普通树
 * @demo initZTree/demo1 动态树、过滤
 * @param {object} opts 用户配置
 * @param {boolean=} opts.multi 是否复选，默认为 false。
 * @param {Array=} opts.data 树数据源，若定义，则 opts.url 及 opts.urlArgs 失效
 * @param {string=} opts.url 树数据源请求地址，若定义了 opts.data，此属性失效
 * @param {object=} opts.urlArgs 树数据源请求时向后台传递的参数，若定义了 opts.data，此属性失效
 * @param {Array=} opts.selParams 指定加载完成后选中项条件[key,value]，复选时，value 支持数组
 * @param {boolean=} opts.initSelect 初始化时若未定义选中项，是否自动点击第一个可选项，默认为 true，复选或显示勾选框时失效。
 * @param {object} opts.filterEl 过滤文本框对象
 * @param {object} opts.filter 过滤功能配置，仅当定义了 filterEl 时生效
 * @param {string|Array} opts.filter.fields 参与过滤的列的属性名，默认与 opts.key.name 相同
 * @param {boolean} opts.filter.pySupport 是否支持拼音首字过滤，开启过滤时，默认为 true
 * @param {string=} opts.filter.placeholder 过滤搜索框占位符(不支持IE8,9)
 * @param {boolean=} opts.filter.hide 是否隐藏不符合过滤条件的节点，单选时默认为 true，复选时默认为 false。<span class="t_green">隐藏节点时会将过滤前的选中项取消选中，复选时建议设为 false。</span>
 * @param {function=} opts.selector(node) 选择时的过滤条件，节点可选时返回 true。
 * @param {object=} opts.async ztree 初始化时的 setting.async
 * @param {object=} opts.check ztree 初始化时的 setting.check。以下属性自定义失效：
 *        opts.multi=true 时，enable=true，chkStyle='checkbox'。
 *        opts.multi=false 时，chkStyle='radio'。
 * @param {object=} opts.callback ztree 初始化时的 setting.callback
 * @param {object=} opts.edit ztree 初始化时的 setting.edit
 * @param {object=} opts.view ztree 初始化时的 setting.view。默认值：
 *        fontCss: function (treeId, treeNode) {// 高亮（过滤）
 *            return (!!treeNode.__hlight) ? {color: "#A60000", "font-weight": "bold"} : {color: "#333", "font-weight": "normal"};
 *        }
 *        selectedMulti: 单选且不显示勾选框时失效，强制为 false
 * @param {object=} opts.key ztree 初始化时的 setting.data.key
 * @param {object=} opts.simpleData ztree 初始化时的 setting.data.simpleData（opts.simple.enable: false 使用/不使用 简单数据模式，默认为树形结构）
 * @param {function=} opts.afterInit(api) 完成初始化后调用的方法
 *        api {object} $.fn.initZTree() 返回的接口
 * @param {function=} opts.onSelect(selnodes,api) 设置选中项后的回调函数。触发时机：初始化完成后，obj.setSel(selParams,bClear)，onClick(单选)/onCheck(复选)
 *        selnodes {object|Array} 单选时为选中节点，复选时为选中节点数组
 *        api {object} $.fn.initZTree() 返回的接口
 * @return {object|undefined} obj 接口对象
 * @rtn {string} obj.treeId 当前树 id
 * @rtn {object} obj.treeObj ztree 初始化完成后获得的树对象
 * @rtn {object} obj.setting ztree 初始化时使用的 setting
 * @rtn {function} obj.fReset(cusOpts) 重置，若未定义参数，则使用初始化时的配置重新初始化树
 *        cusOpts {object=} 将覆盖初始化时的参数，暂只支持 data, url, urlArgs, selParams
 * @rtn {function} obj.reset(url,urlArgs,selParams) <span class="t_gray80">请用 obj.fGetResultData() 替代。</span>
 * @rtn {function} obj.reset(data,selParams) <span class="t_gray80">请用 obj.fGetResultData() 替代。</span>
 * @rtn {function} obj.setSel(selParams,bClear) 设置选中项
 *        selParams {Array=} 指定要选中的项的条件[key,value]，复选时 value 支持数组
 *        bClear {boolean=} 是否先清空原有选中项，默认为 true
 * @rtn {function} obj.getNodeById(tId) 根据 tid 获取节点，返回值 {object} 节点数据
 *        tId {string} ztree 中的节点标识 tid
 * @rtn {function} obj.getSelectedNodes() 单选返回选中项，无则返回 undefined；复选返回选中项数组（含半选），无则返回[]
 * @rtn {function} obj.getSelectedNodesNoHalf() 单选同obj.getSelectedNodes()；复选返回选中项数组（不含半选），无则返回[]
 */
$.fn.initZTree = function(opts){
    var el = $(this);
    opts = $.extend({
        multi: false,// 默认单选
        //data:[],
        //url:'',
        //urlArgs:{},
        //selParams:[key,val],
        initSelect: true,
        //filterEl,
        filter: {}
        //selector:function(node),
        //async,check,callback,edit,view,key,simpleData,
        //afterInit:function(api),
        //onSelect:function(selnodes,api),
    }, opts);
    var _conf = {// 辅助参数
        filterRemains: 0,// 搜索关键字时修改节点高亮属性及展开父节点（会造成延时）的剩余操作总数
        scrollNode: undefined,// 要移入视图的节点
        filtering: false,
        filterList: [],// 高亮节点列表 / 隐藏节点列表
        initing: false,// 标记是否处于初始化过程，避免初始化时展开选中节点的祖先的操作进入 _afterFilterOpt 导致无法完成初始化及触发用户回调
        selChanging: false// 是否正在调整选中项，_afterFilterOpt 中触发 onSelect 事件
    };
    var treeId,// 树 id
        oTreeSetting,// ztree 初始化时的参数
        oZTree,// ztree 初始化完成后返回的接口对象，在 initTree() 中赋值
        bCheckable,// 是否显示勾选框
        aNodesArr,// 数组型节点数据源，在 initTree() 中赋值
        bMulti,// 是否复选
        oClickNode;// 单选且不显示勾选框在初始化时点击的节点，若存在将在 _afterFilterOpt 中触发点击
    var api, oFilterApi;

    // 过滤完成后，显示结果
    var _filterNodes = function(filterNodes, keyword){
        var selNodes;
        if(!oFilterApi) return;// 过滤组件初始化过程中，关键字为 ''，不执行过滤，否则将清空点击状态
        _conf.filtering = true;
        if(opts.filter.hide){
            if(!_conf.initing){// 非初始化的过滤才将原选中项取消，否则导致 oFilterApi.resetData() 时将默认选中项清空
                selNodes = fGetSelectedNodes();
                if(selNodes){
                    if(bMulti){// 多选
                        for(var i = 0, sLen = selNodes.length; i < sLen; i++){
                            oZTree.checkNode(selNodes[i], false, false);
                        }
                    }
                    else{// 单选
                        if(bCheckable){// 可勾选
                            oZTree.checkNode(selNodes, false);
                        }
                        else{
                            oZTree.cancelSelectedNode(selNodes);
                        }
                    }
                }
            }
            showFilter(filterNodes, keyword);// 显示过滤结果
        }
        else{
            highlight(_conf.filterList, false);
            if(keyword){
                _conf.filterList = filterNodes;
                filterNodes && filterNodes.length && highlight(filterNodes, true);
            }
        }
    };

    var _scrollTo = function(node){
        if(node){
            _conf.filtering = true;
            _conf.filterRemains++;
            _conf.scrollNode = node;
            _expandAncestors(node);
        }
        else if(_conf.scrollNode){// 不定义滚动项时默认滚动到 _conf.scrollNode
            var nodeId = _conf.scrollNode.tId.replace(/\s/g, '_');
            var _treeDom = document.getElementById(treeId);
            var _treeBCR = _treeDom.getBoundingClientRect(),
                _nodeBCR = document.getElementById(nodeId).getBoundingClientRect(),
                nNodeH = WICONF.initZTree.nNodeH;
            if(_nodeBCR.top + nNodeH > _treeBCR.bottom){
                _treeDom.scrollTop += _nodeBCR.top + nNodeH - _treeBCR.bottom;
            }
            else if(_nodeBCR.top < _treeBCR.top){
                _treeDom.scrollTop += _nodeBCR.top - _treeBCR.top;
            }
            //document.getElementById(nodeId).scrollIntoView();// 此方法会将过滤节点滚动到最顶，即时它原本就在可视区。网上说安卓中的浏览器对此方法支持不好
            _conf.scrollNode = undefined;
        }
    };
    /**
     * 搜索到的所有节点的祖先节点及属性修改完成后，将 _conf.scrollNode 对应的节点滚入视图
     */
    var _afterFilterOpt = function(){
        if(_conf.filtering && _conf.filterRemains == 0){// 所有节点操作完成，使第一个高亮节点进入视图
            if(_conf.initing){// 在初始化过程中
                oFilterApi && oFilterApi.setData(aNodesArr);
                _conf.initing = false;// 必须在 oFilterApi.setData 之后，否则会被清空选中项
                opts.afterInit && opts.afterInit(api);
            }
            if(_conf.selChanging){// 正在修改选中项
                _conf.selChanging = false;
                if(oClickNode){// oClickNode 存在：单选且有选中项
                    $('#' + oClickNode.tId + '_a').click();// 点击要选中的项，onClick 事件中会触发 onSelect
                    oClickNode = undefined;
                }
                else{// 复选或无选中项
                    opts.onSelect && opts.onSelect(fGetSelectedNodesNoHalf(), api);
                }
            }
            _scrollTo();
            _conf.filtering = false;
        }
    };
    /**
     * 选中指定项
     * @param selParams {Array=} 指定加载完成后选中项条件[key,value]，复选时，value支持数组
     * @param bClear {boolean=} 是否要清除原有选中项，默认为 true，初始化时失效
     * @private
     */
    var fSetSel = function(selParams, bClear){
        var len = aNodesArr.length;
        var key, val, aVal,
            firstEnableNode,// 第一个可选节点
            i, node,// 循环临时变量
            selectedNodes;// 原来选中的项
        bClear = bClear !== false;
        _conf.scrollNode = undefined;
        _conf.filtering = true;
        _conf.selChanging = true;// 正在改变选中值
        if(len > 0){
            if(selParams){// 要设置的选中项
                key = selParams[0];
                if(key){
                    val = selParams[1];
                    aVal = Object.prototype.toString.call(val) === '[object Array]' ? val : [val];
                }
            }
            selectedNodes = fGetSelectedNodes();// 原来选中的项
            // 清除所有选中项
            if(bClear && selectedNodes){
                if(bMulti){
                    for(i = 0; i < selectedNodes.length; i++){
                        oZTree.checkNode(selectedNodes[i], false);
                    }
                }
                else{
                    if(bCheckable){
                        oZTree.checkNode(selectedNodes, false);
                    }
                    else{
                        oZTree.cancelSelectedNode(selectedNodes);
                    }
                }
            }
            // 设置新的选中项
            selectedNodes = undefined;
            if(bCheckable){// 显示勾选框
                if(_conf.initing){
                    for(i = 0; i < len; i++){// 根据 selParams 及 selector 勾选，并隐藏不可选的节点的勾选框
                        node = aNodesArr[i];
                        if(!opts.selector || opts.selector(node)){// 未定义 selector，或符合 selector
                            if(!firstEnableNode){
                                firstEnableNode = node;
                            }
                            if(key && aVal.indexOf(node[key]) > -1){// 符合 selParams
                                oZTree.checkNode(node, true, false);// 因为可能存在由数据源决定的选中状态，故最后统一处理级联
                            }
                        }
                        else{// 不可选的节点隐藏复选框
                            node['nocheck'] = true;
                            oZTree.updateNode(node);
                        }
                    }
                }
                else{
                    for(i = 0; i < len; i++){// 根据 selParams 及 selector 勾选，并隐藏不可选的节点的勾选框
                        node = aNodesArr[i];
                        if(!opts.selector || opts.selector(node)){// 未定义 selector，或符合 selector
                            if(key && val.indexOf(node[key]) > -1){// 符合 selParams
                                oZTree.checkNode(node, true, false);// 因为可能存在由数据源决定的选中状态，故最后统一处理级联
                            }
                        }
                    }
                }

                // 统一处理级联，根据选中的项设置级联父子节点
                // 复选且允许级联，手动选中各项，以触发级联选中
                if(bMulti && oTreeSetting.check.chkboxType.Y){
                    selectedNodes = api.getSelectedNodes();// 获取当前勾选项集合（初始化时均未级联）
                    for(i = 0, len = selectedNodes.length; i < len; i++){
                        oZTree.checkNode(selectedNodes[i], true, true);
                    }
                }

                selectedNodes = fGetSelectedNodesNoHalf();// 获取最终的选中集合（不含半选项）
            }
            else{// 单选且不支持勾选
                for(i = 0; i < len; i++){// 根据 selParams 及 selector 勾选
                    node = aNodesArr[i];
                    if(!opts.selector || opts.selector(node)){// 未定义 selector，或符合 selector
                        if(!firstEnableNode){
                            firstEnableNode = node;
                        }
                        if(key && val === node[key]){// 符合 selParams
                            selectedNodes = node;// 获取最终的选中集合（不含半选项）
                            break;
                        }
                    }
                }
                // 设置要触发点击事件的节点
                if(selectedNodes){
                    oClickNode = selectedNodes;
                }
                else{
                    if(_conf.initing && opts.initSelect){// 初始化时，要求有默认选中
                        oClickNode = firstEnableNode;
                    }
                }
            }
            // 展开选中项的祖先节点，并设置要滚入视图的节点
            if(bMulti){// 多选
                len = selectedNodes.length;
                if(len){// 有选中项
                    _conf.filterRemains += len;
                    for(i = 0; i < len; i++){// 展开所有选中项
                        node = selectedNodes[i];
                        !_conf.scrollNode && (_conf.scrollNode = node);// 记录第一项过滤层级的节点（非半选项）
                        _expandAncestors(node);
                    }
                }
                else if(_conf.initing && firstEnableNode){// 初始化时默认展开第一个可选项
                    _conf.filterRemains++;
                    _conf.scrollNode = firstEnableNode;
                    _expandAncestors(_conf.scrollNode);
                }
            }
            else{// 单选
                _conf.scrollNode = _conf.initing && !selectedNodes
                    ? firstEnableNode : selectedNodes;
                if(_conf.scrollNode){
                    _conf.filterRemains++;
                    _expandAncestors(_conf.scrollNode);
                }
            }
        }
        _afterFilterOpt();
    };
    // 初始化 ztree 组件，并执行初始选中
    var fInitZTree = function(data){
        if(typeof(data) === 'string'){
            data = JSON.parse(data);
        }
        oZTree && oZTree.destroy(treeId);
        _conf.filterList.length = 0;
        oZTree = api.treeObj = $.fn.zTree.init($('#' + treeId), oTreeSetting, data || []);
        aNodesArr = oZTree.transformToArray(oZTree.getNodes());
        _conf.initing = true;// 标识正在进行初始化，完成后在 _afterFilterOpt() 中处理初始化回调
        fSetSel(opts.selParams, false);
    };

    /**
     * 展开指定节点的所有祖先
     * @param node {object} 树中的节点对象
     * @private
     */
    var _expandAncestors = function(node){
        var level = node['level'],
            pnode = node;
        while(level > 0){
            pnode = pnode.getParentNode();
            if(pnode.open == false){
                _conf.filterRemains++;// 新增一个父节点操作
                /* 展开父节点，完成后触发 onExpand */
                oZTree.expandNode(pnode, true, false, false, true);
                break;// expandNode 操作会展开父级节点
            }
            level--;
        }
        _conf.filterRemains--;
        _afterFilterOpt();
    };

    var showFilter = function(nodeList, keyword){
        _conf.filtering = true;
        var nodes = oZTree.getNodes();
        var childrenField = oZTree.setting.data.key.children;
        /**
         * @return {boolean} nodes 中是否存在需要显示的节点
         */
        var chargeNodes = function(nodes){
            if(!nodes || !nodes.length) return false;
            var show = false;
            for(var i = 0, node, children, nodeShow = false; i < nodes.length; i++){
                node = nodes[i];
                children = node[childrenField];
                nodeShow = chargeNodes(children);// 先判断子孙中是否有匹配的节点
                if(!keyword){
                    node.__hlight = false;
                    nodeShow = true;
                }
                else if(nodeList.indexOf(node) > -1){// 当前节点匹配
                    node.__hlight = true;
                    nodeShow = true;
                }
                else{
                    node.__hlight = false;
                }
                if(nodeShow){
                    oZTree.showNode(node);
                }
                else{
                    oZTree.hideNode(node);
                    _conf.filterList.push(node);
                }
                oZTree.updateNode(node);// 更新节点状态
                show = show || nodeShow;
            }
            return show;// 没有匹配的子节点
        };
        _conf.filterList.length = 0;
        chargeNodes(nodes);
        if(keyword) oZTree.expandAll(true);// 搜索结果全部展开
    };

    var highlight = function(nodeList, highlight){
        if(!nodeList) return;
        var i, node;// 循环临时变量
        if(highlight){// 开启高亮
            var scrollNode;
            _conf.filterRemains = nodeList.length;// 等待完成的节点操作总数，初始时为搜索到的节点总数（展开节点会产生延迟）
            for(i = 0; i < nodeList.length; i++){
                node = nodeList[i];
                !scrollNode && (!bMulti || !node.getCheckStatus.half) && (scrollNode = _conf.scrollNode = node);// 记录第一项过滤层级的节点（非半选项）
                node.__hlight = true;
                oZTree.updateNode(node);
                _expandAncestors(node);// 展开所有高亮节点的祖先
            }
        }
        else{// 取消高亮
            for(i = 0; i < nodeList.length; i++){
                node = nodeList[i];
                node.__hlight = false;
                oZTree.updateNode(node);
            }
        }
    };

    // TODO del 兼容旧版本
    // 更新数据源，重新初始化树 reset(url,urlArgs,selParams);reset(data,selParams)
    var _reset = function(url, urlArgs, selParams){
        var _data, _url, _urlArgs, _selParams;
        // 参数处理
        if(typeof url === 'string'){
            _url = url;
        }
        else if(Object.prototype.toString.call(url) === '[object Array]'){
            _data = url;
        }
        if(Object.prototype.toString.call(urlArgs) === '[object Array]'){
            _selParams = urlArgs;
        }
        else if(urlArgs){
            _urlArgs = urlArgs
        }
        if(selParams){
            _selParams = selParams;
        }
        // 重置
        fReset({
            url: _url,
            urlArgs: _urlArgs,
            data: _data,
            selParams: _selParams
        });
    };

    // 获取选中项，复选返回数组（含半选项），单选返回对象
    var fGetSelectedNodes = function(){
        var aSel = bCheckable ?// 是否显示勾选框
            oZTree.getCheckedNodes(true) :
            oZTree.getSelectedNodes(true);
        return bMulti ? aSel : aSel[0];
    };

    var fGetSelectedNodesNoHalf = function(){
        var selNodes = fGetSelectedNodes();
        if(bMulti){
            var result = [];
            for(var i = 0, len = selNodes.length, node; i < len; i++){
                node = selNodes[i];
                !node.getCheckStatus().half && result.push(node);// 只保留非半选的节点
            }
            return result;
        }
        return selNodes;
    };

    // 根据用户配置初始化 zTree setting
    var fInitSetting = function(){
        oTreeSetting = {
            async: opts.async || {},
            callback: opts.callback || {},
            check: opts.check || {},
            data: {
                key: opts.key,
                simpleData: opts.simpleData
            },
            edit: opts.edit || {},
            view: $.extend({}, WICONF.initZTree.view, opts.view)
        };
        var sSelFnName,// 改变选中状态的事件名称
            oCheck = oTreeSetting.check;
        /* 处理可能冲突的配置 */
        if(bMulti){// 复选
            oCheck.enable = true;
            oCheck.chkStyle = 'checkbox';
            oCheck.chkboxType = {Y: 'ps', N: 'ps'};// 后续操作中需要 chkboxType 字段，必须定义默认值
        }
        else{// 单选
            oCheck.chkStyle = 'radio';
            oCheck.radioType = 'all';// TODO 'level' 暂未实现设置选中项时，判断同一个父节点下的互斥关系
            if(!oCheck.enable){// 不显示勾选框
                oTreeSetting.view.selectedMulti = false;
            }
        }
        bCheckable = oCheck.enable;
        // 必须在 enable 完成处理后赋值
        sSelFnName = bCheckable ? 'onCheck' : 'onClick';
        /* 封装默认的回调方法 */
        // 因为聚焦元素时会展开节点（异步），所以要加入默认操作
        oTreeSetting.callback.onExpand = (function(_onExtend){
            return function(event, treeId, node){
                if(_conf.filtering){// 过滤时展开完成，操作总数-1，不执行用户操作
                    _conf.filterRemains--;
                    _afterFilterOpt();
                }
                else{
                    _onExtend(event, treeId, node);
                }
            }
        })(oTreeSetting.callback.onExpand || $.noop);
        // 设置选中项后的回调函数
        if(opts.onSelect){
            oTreeSetting.callback[sSelFnName] = (function(fn){
                return function(){
                    fn.apply(this, arguments);
                    opts.onSelect(fGetSelectedNodesNoHalf(), api);
                }
            })(oTreeSetting.callback[sSelFnName] || $.noop);
        }
        // 不显示勾选框且定义了选择时的过滤条件（显示勾选框时，在初始化时对数据源 nocheck 属性设置隐藏复选框）
        if(!bCheckable && opts.selector){
            oTreeSetting.callback.beforeClick = (function(_beforeClick){
                return _beforeClick ?
                    function(treeId, node, flag){
                        return opts.selector(node) && _beforeClick(treeId, node, flag);
                    } :
                    function(treeId, node, flag){
                        return opts.selector(node);
                    }
            })(oTreeSetting.callback.beforeClick);
        }
        api.setting = oTreeSetting;
    };

    // 初始化过滤支持，数据源需在数据加载完成后绑定
    var fInitFilter = function(){
        if(!opts.filterEl) return;
        var oFilter = $.extend({}, opts.filter);
        if(!oFilter.fields && opts.key && opts.key.name){
            oFilter.fields = opts.key.name;
        }
        if(oFilter.hide === undefined){
            oFilter.hide = !bMulti;// 多选默认为 true，多选默认为 false
        }
        oFilterApi = opts.filterEl.initFilter({
            fields: oFilter.fields,
            placeholder: oFilter.placeholder,
            pySupport: oFilter.pySupport,
            afterFilter: _filterNodes
        });
    };

    // 绑定数据源，将重新初始化 zTree 组件
    var fBindData = function(){
        if(opts.url){
            $.ajax({// 请求数据初始化树
                type: 'post',
                dataType: 'json',
                url: opts.url,
                data: opts.urlArgs || {},
                success: function(result){
                    if(!result.success){
                        result.msg && $.showAlert(result.msg);
                        return;
                    }
                    fInitZTree(result.data);
                }
            });
        }
        else{
            fInitZTree(opts.data || []);
        }
    };

    // 修改初始化时的配置（暂只支持 data, url, urlArgs, selParams），重新获取数据
    var fReset = function(cusOpts){// fInit 中调用时传入 true
        var bResetData = false,// 是否需要重置数据源，需要初始化 zTree
            bResetSel = false;// 是否需要重置选中项
        if(typeof cusOpts == 'object'){
            // 扩展配置
            $.extend(opts, cusOpts);
            // 数据配置
            if(cusOpts.data){// 重设了 data，将 url 置空
                bResetData = true;
            }
            else if(cusOpts.url){// 重设了 url，将 data 置空，并清空查询条件
                bResetData = true;
                delete opts.data;
                opts.urlArgs = cusOpts.urlArgs || {};
            }
            else if(opts.url && cusOpts.urlArgs){// 只重设请求参数
                bResetData = true;
            }
            if(bResetData){// 数据源发生变化，同步重置选中项
                opts.selParams = cusOpts.selParams;
            }
        }
        else if(cusOpts === true){// 初始化时，处理 opts
            bResetData = true;
            fInitSetting();
        }
        /* 应用配置 */
        if(bResetData){
            fInitFilter();
            // 数据配置
            if(opts.data){
                delete opts.url;
                delete opts.urlArgs;
            }
            fBindData();
        }
        else if(bResetSel){
            fSetSel(opts.selParams, true);
        }
    };

    // 获取指定节点数据，直接调用 oZTree 可能未完成初始化
    var fGetNodeById = function(tId){
        return oZTree.getNodeByTId(tId);
    };

    var fInit = function(){
        el.addClass('ztree');
        treeId = el.attr('id');// 树 id，同步到 api
        if(!treeId){
            treeId = $.generateGuid('zTree');
            el.attr('id', treeId);
        }
        api.treeId = treeId;
        bMulti = opts.multi;
        fReset(true);
    };

    api = {
        //treeId: treeId,// 初始化时赋值
        //setting: 初始化 zTree 时的配置，初始化时调用 fInitSetting() 赋值
        fReset: fReset,// 更新数据源
        setSel: fSetSel,
        reset: _reset,// TODO del 兼容旧版本，现通过 fReset() 实现
        getNodeById: fGetNodeById,
        getSelectedNodes: fGetSelectedNodes,// 复选时，含半选项
        getSelectedNodesNoHalf: fGetSelectedNodesNoHalf// 复选时，不含半选项
    };
    fInit();
    return api;
};